// Fill out your copyright notice in the Description page of Project Settings.

#include "Isalong2.h"
#include "CPlayerCharacter.h"
#include "GunCustomLogicBase.h"


AWeaponGunBase::AWeaponGunBase()
{
	_tookUpBox = CreateDefaultSubobject<UBoxComponent>(TEXT("TookUpBox"));
	_tookUpBox->AttachTo(_skMesh);
	_tookUpBox->SetCollisionProfileName(TEXT("BuildingTrace"));
	// for pick up
	_tookUpBox->SetBoxExtent(FVector(5, 10, 10));
}

IWeaponOwner* AWeaponGunBase::GetWeaponOwner()
{
	return _weaponOwner;
}

USkeletalMeshComponent* AWeaponGunBase::GetSKMesh()
{
	return _skMesh;
}

void AWeaponGunBase::Tick(float DeltaSeconds)
{
	Super::Tick(DeltaSeconds);

	// for unknown reason the tick no work use this instead
	for (int i = 0; i < _gunLogics.Num(); i++)
	{
		if (_gunLogics[i]->Get_UseLogicTick())
		{
			_gunLogics[i]->LogicTick(DeltaSeconds);
			return;
		}
	}
}

void AWeaponGunBase::OnReloadBegin()
{
	// for logic check
	for (int i=0;i<_gunLogics.Num();i++)
	{
		if (_gunLogics[i]->Get_Override_OnReloadBegin())
		{
			_gunLogics[i]->OnReloadBegin();
			return;
		}
	}

	if (_dataPack->_weaponReloadMontage != nullptr)
	{
		_skMesh->GetAnimInstance()->Montage_Play(_dataPack->_weaponReloadMontage);
		if (_weaponOwner != nullptr&&_dataPack->_characterReloadMontage != nullptr)
		{
			_weaponOwner->OnPlayMontage(_dataPack->_characterReloadMontage);
			if (_dataPack->_reloadSound!=nullptr)
			{
				UGameplayStatics::PlaySoundAtLocation(this, _dataPack->_reloadSound, GetActorLocation());
			}
		}
	}

	for (int i = 0; i < _gunLogics.Num(); i++)
	{
		_gunLogics[i]->OnReloadBegin_Addition();
	}
}

void AWeaponGunBase::OnReloadEnd(int count)
{
	// for logic check
	for (int i=0;i<_gunLogics.Num();i++)
	{
		if (_gunLogics[i]->Get_Override_OnReloadEnd())
		{
			_gunLogics[i]->OnReloadEnd(count);
			return;
		}
	}

	SetBulletContains(GetBulletContains() + count, true);
	if (_weaponOwner != nullptr)
	{
		_weaponOwner->OnBulletChangeCallBack();
	}
}

void AWeaponGunBase::OnFireAnimationEnd()
{
	for (int i = 0; i < _gunLogics.Num(); i++)
	{
		if (_gunLogics[i]->Get_Override_OnFireAnimationEnd())
		{
			_gunLogics[i]->OnFireAnimationEnd();
			return;
		}
	}
}

void AWeaponGunBase::OnFireAnimationFired()
{
	for (int i = 0; i < _gunLogics.Num(); i++)
	{
		if (_gunLogics[i]->Get_Override_OnFireAnimationFired())
		{
			_gunLogics[i]->OnFireAnimationFired();
			return;
		}
	}
}

void AWeaponGunBase::PickUp(IWeaponOwner* character)
{
	Super::PickUp(character);
	for (int i = 0; i < _gunLogics.Num(); i++)
	{
		_gunLogics[i]->PickUp_Addition(character);
	}
}

void AWeaponGunBase::PutDown(IWeaponOwner* character)
{
	Super::PutDown(character);
	for (int i = 0; i < _gunLogics.Num(); i++)
	{
		_gunLogics[i]->PutDown_Addition(character);
	}
}

void AWeaponGunBase::OnFireBegin()
{
	for (int i=0;i<_gunLogics.Num();i++)
	{
		if (_gunLogics[i]->Get_Override_OnFireBegin())
		{
			_gunLogics[i]->OnFireBegin();
			return;
		}
	}

	ToolPistolFireBegin();
}

void AWeaponGunBase::OnFireEnd()
{
	for (int i = 0; i < _gunLogics.Num(); i++)
	{
		if (_gunLogics[i]->Get_Override_OnFireEnd())
		{
			_gunLogics[i]->OnFireEnd();
			return;
		}
	}
}

int AWeaponGunBase::GetAdditionValue()
{
	return GetBulletContains();
}

TArray<int> AWeaponGunBase::GetReloadNeedType()
{
	return ItemType::GetReloadNeedType(_itemType);
}

void AWeaponGunBase::ToolPistolFireBegin()
{
	if (GetBulletContains() == 0)
	{
		return;
	}
	if (_dataPack->_weaponFireMontage != nullptr)
	{
		_skMesh->GetAnimInstance()->Montage_Play(_dataPack->_weaponFireMontage);
		if (_weaponOwner!=nullptr&&_weaponOwner->IsAuxiliaryMode()&&_dataPack->_characterADSMontage!=nullptr)
		{
			_weaponOwner->OnPlayMontage(_dataPack->_characterADSMontage);
		}
		if (_weaponOwner!=nullptr&&!_weaponOwner->IsAuxiliaryMode()&&_dataPack->_characterFireMontage!=nullptr)
		{
			_weaponOwner->OnPlayMontage(_dataPack->_characterFireMontage);
		}
	}
	if (_dataPack->_fireSound != nullptr)
	{
		UGameplayStatics::PlaySoundAtLocation(this, _dataPack->_fireSound, GetActorLocation());
	}
	if (((FGunData*)_dataPack)->_shellDropSound!=nullptr)
	{
		UGameplayStatics::PlaySoundAtLocation(this, ((FGunData*)_dataPack)->_shellDropSound, GetActorLocation());
	}
	if (_dataPack->_fireShake!=nullptr&&Cast<ACPlayerCharacter>(_weaponOwner)!=nullptr)
	{
		UGameplayStatics::GetPlayerCameraManager(this, 0)->PlayCameraShake(_dataPack->_fireShake);
	}
	if (_dataPack->_weaponFireParticle!=nullptr)
	{
		// add fire particle effect
		_particleSys->SetTemplate(_dataPack->_weaponFireParticle);
		_particleSys->Activate(true);
	}
	auto hitresult= ToolRayTrace(GetGunPortLocation(), GetGunPortLocation() + 10000*(_forwardArrow->GetForwardVector() + FVector(((FGunData*)_dataPack)->_gunSourceBias*FMath::RandRange(0,3), ((FGunData*)_dataPack)->_gunSourceBias*FMath::RandRange(0, 3), ((FGunData*)_dataPack)->_gunSourceBias*FMath::RandRange(0, 3))), false, true,true);
	if (hitresult.GetActor()!=nullptr)
	{
		FTransform tf;
		tf.SetLocation(hitresult.Location);
		AFireEffect* effectTemp= GetWorld()->SpawnActor<AFireEffect>(AFireEffect::StaticClass(),tf);
		effectTemp->SetActorRelativeRotation(FRotationMatrix::MakeFromX(hitresult.ImpactNormal).Rotator());
		UPhysicalMaterial* const HitPhysMat = hitresult.PhysMaterial.Get();
		effectTemp->SetUpParticle(ResourceManager::GetResourceManager()->GetFireHitEffect(UPhysicalMaterial::DetermineSurfaceType(HitPhysMat), EFFECT_SIZE_DEFAULT, EFFECT_WEAPON_DEFAULT));
		// try hurt actor
		auto hurtable = Cast<IBeHurtable>(hitresult.GetActor());
		// when is not null
		if (hurtable!=nullptr)
		{
			hurtable->OnHurt((AActor*)_weaponOwner, hitresult.ImpactNormal, hitresult.Location, _dataPack->_hurtType,_dataPack->_baseHurtValue,hitresult.GetComponent());
			if (hitresult.GetComponent()!=nullptr&&hitresult.GetComponent()->IsSimulatingPhysics())
			{
				hitresult.GetComponent()->AddImpulseAtLocation(5000*( hitresult.TraceEnd-hitresult.TraceStart).GetSafeNormal(1), hitresult.Location);
			}
		}
	}
	if (hitresult.GetActor()!=nullptr)
	{
		FTransform tf;
		ABulletDecalBase* decalBt;
		tf.SetLocation(hitresult.Location);
		tf.SetRotation(FRotationMatrix::MakeFromX(hitresult.ImpactNormal).Rotator().Quaternion());
		decalBt = GetWorld()->SpawnActor<ABulletDecalBase>(ABulletDecalBase::StaticClass(), tf);
		check(decalBt != nullptr);
		if (_decalEffect!=nullptr)
		{
			decalBt->SetMat(_decalEffect);
		}
		else
		{
			decalBt->SetMat(ResourceManager::_resourceManager->_bulletDecalMat);
		}
	}
	SetBulletContains(GetBulletContains() - 1, true);
	if (_weaponOwner != nullptr)
	{
		// for display ui
		_weaponOwner->OnBulletChangeCallBack();
	}
}

void AWeaponGunBase::SetUpData(FInteractData* data, int itemType)
{
	_dataPack = (FWeaponPack*)data;
	_itemType = itemType;
	SetBulletContains(_dataPack->_maxContains, false);
	_skMesh->SetSkeletalMesh(_dataPack->_skeletalMesh);
	_skMesh->SetAnimInstanceClass(_dataPack->_weaponAnimBP);
	_forwardArrow->SetRelativeLocation(_dataPack->_forwardArrowLocationOffset);
	_forwardArrow->SetRelativeRotation(_dataPack->_forwardArrowRotationOffset);
	_particleSys->SetRelativeRotation(_dataPack->_effectParticleRotationOffset);
	_particleSys->SetRelativeLocation(_dataPack->_effectParticleLocationOffset);
	_itemType = itemType;

	// construct logic
	TArray<UClass*> logics = ((FGunData*)_dataPack)->_logics;
	for (int i =0;i<logics.Num();i++)
	{
		UGunCustomLogicBase* gunLogicComponent = ConstructObject<UGunCustomLogicBase>(logics[i], this);
		if (gunLogicComponent)
		{
			gunLogicComponent->RegisterComponent();
			gunLogicComponent->Init(this);
			_gunLogics.Add(gunLogicComponent);
		}
	}
}

void AWeaponGunBase::SetupAdditionValue(int val)
{
	for (int i=0;i<_gunLogics.Num();i++)
	{
		if (_gunLogics[i]->Get_Override_SetupAdditionValue())
		{
			_gunLogics[i]->SetupAdditionValue(val);
			return;
		}
	}

	SetBulletContains(val, false);
}